package com.epcs.model.dao;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import com.epcs.model.dto.Account;
import com.epcs.model.dto.Event;
import com.epcs.model.dto.Eventcategory;
import com.epcs.model.dto.Following;
import com.epcs.util.DBUtil;
import com.epcs.util.EpcsDateTimeUtil;

public class EventDAO {

	// thêm mới một Event
	public int addEvent(Event event) {

		Session session = DBUtil.getSession();
		Transaction trans = null;
		try {
			trans = session.beginTransaction();
			session.save(event);
			trans.commit();
			// Lay id cua event moi tao ra
			int newEventID = event.getEventId();
			// return ve event id moi
			return newEventID;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
			trans.rollback();
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return 0;
	}

	public Eventcategory getEventCategoryByID(String id) {

		Eventcategory eventcategorybyid = new Eventcategory();
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Eventcategory.class);
			Integer category = Integer.parseInt(id);
			criteria.add(Restrictions.eq("eventCategoryId", category));
			eventcategorybyid = (Eventcategory) criteria.uniqueResult();
			if (eventcategorybyid != null)

				return eventcategorybyid;
		} finally {

			if (session != null) {
				session.close();
			}
		}
		return null;
	}

	// Lay tat ca Event thuoc ve 1 user
	public List<Event> getEventListFromDB(Account account) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("status", "confirmed"));									
			criteria.addOrder(Order.asc("startTime"));									
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}
	// Lay tat ca Event thuoc ve 1 user
	public List<Event> getEventListFromDBForSync(Account account) {
		
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.eq("account", account));									
			criteria.addOrder(Order.asc("startTime"));									
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}
		
		return null;
	}

	/**
	 * Lay tat ca Event con đã tạo khi follow 1 event chính. Sử dụng event chính
	 * để tìm.
	 * 
	 * @param account
	 * @return
	 */
	public List<Event> getSubEventFromDB(Event originalEvent) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion = Restrictions.eq("originalEvent",
					originalEvent);
			criteria.add(criterion);
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// Lay tat ca Event thuoc ve 1 user (dùng cho android)
	public List<Event> getEventListFromDBForAndroid(Account account) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.eq("account", account)).add(
					Restrictions.eq("dirty", Boolean.valueOf(true)));
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// Update 1 event hien tai
	public boolean updateEvent(Event event) {

		Session session = DBUtil.getSession();
		Transaction trans = null;
		try {
			trans = session.beginTransaction();
			session.update(event);
			trans.commit();
			return true;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
			trans.rollback();
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return false;
	}

	// Xoa event
	public boolean deleteEvent(Event event) {

		Session session = DBUtil.getSession();
		Transaction trans = null;
		try {
			trans = session.beginTransaction();
			session.delete(event);
			trans.commit();
			return true;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
			trans.rollback();
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return false;
	}

	public List<Event> getEventByDatetime(String start, String end,
			Account account) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.gt("startTime", start))
					.add(Restrictions.lt("endTime", end))
					.add(Restrictions.eq("account", account));
			List<Event> list = criteria.list();
			if (list.size() > 0)
				return list;
		} finally {

			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// Lay 1 event ra dua vao id truyen vao
	public Event getEventFromDB(int eventId) {
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion = Restrictions.eq("eventId", eventId);
			criteria.add(criterion);
			Event item = (Event) criteria.uniqueResult();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// Tao follow
	public int addFollow(Following follow) {

		Session session = DBUtil.getSession();
		Transaction trans = null;
		try {
			trans = session.beginTransaction();
			session.save(follow);
			trans.commit();
			// Lay id cua follow moi tao ra
			int newFollowID = follow.getFollowingId();
			// return ve follow id moi
			return newFollowID;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
			trans.rollback();
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return 0;
	}

	// Lay tat ca public Event
	public List<Event> getPublicEventListFromDB(Account account) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion = Restrictions.eq("visibility", "public");

			criteria.add(criterion).add(
					Restrictions.not(Restrictions.eq("account", account)));

			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// Lay public event theo category rồi

	public List<Event> getPublicEventListByCategory(Eventcategory category) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion = Restrictions.eq("visibility", "public");
			Criterion criterion1 = Restrictions.eq("eventcategory", category);
			criteria.add(criterion);
			criteria.add(criterion1);
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	public Event getEventByEventId(int eventId) {

		Integer num = Integer.valueOf(eventId);
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion = Restrictions.eq("eventId", num);
			criteria.add(criterion);
			Event item = (Event) criteria.uniqueResult();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	// Lay tat ca Event co OrginalEventId = id truyen vao
	public List<Event> getEventListByOrinalId(Event event) {

		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion = Restrictions.eq("originalEvent", event);
			criteria.add(criterion);
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}

	/**
	 * position: - endTime,startTime
	 * 
	 * @param listEventCategory
	 * @param position
	 * @return
	 */
	public List<Integer> getEventIdListByUserCategory(List<Eventcategory> listEventCategory, String position, Account account) {
		String currentTime = EpcsDateTimeUtil.getCurrentIsoDateTime();
		FollowingDAO followingDAO = new FollowingDAO();
		if (listEventCategory != null) {
			Session session = DBUtil.getSession();
			try {
				Criteria criteria = session.createCriteria(Event.class);

				/**
				 * Nếu account không null, tức là tìm những event không phải của
				 * nó Mục tiêu: lấy những sự kiện không follow,và sắp xếp theo
				 * thứ tự tăng dần theo thời gian (position)
				 */
				if (account != null) {
					criteria.add(Restrictions.not(Restrictions.eq("account", account)))
							.addOrder(Order.asc(position));
					//
					List<Integer> eventIdList = followingDAO
							.getEventIdListByAccount(account);
					if (eventIdList != null) {
						criteria.add(Restrictions.not(Restrictions.in(
								"eventId", eventIdList)));
					}
				}
				/**
				 * Lấy event chưa hết hạn, là public event, được quan tâm theo
				 * category
				 */
				criteria.add(Restrictions.gt(position, currentTime))
						.add(Restrictions.eq("visibility", "public"))
						.add(Restrictions.eq("status", "confirmed"))
						.add(Restrictions
								.in("eventcategory", listEventCategory))
						.setProjection(
								Projections.projectionList().add(
										Projections.property("eventId")));
				// lấy list eventId
				List<Integer> item = criteria.list();
				return item;
			} catch (HibernateException e) {
				System.out.println(e.getMessage());
			} finally {
				if (session != null) {
					session.close();
				}
			}
		}
		return null;
	}

	public List<Event> getEventListAfterFilter(int firstPosition, int maxRecord, List<Integer> eventIdList) {
		List<Event> item = new ArrayList<Event>();
		if (eventIdList != null) {
			
			Session session = DBUtil.getSession();
			try {
				Criteria criteria = session.createCriteria(Event.class);
				criteria.add(Restrictions.in("eventId", eventIdList))
						.setFirstResult(firstPosition).setMaxResults(maxRecord);
				
				item = criteria.list();
				
			} catch (HibernateException e) {
				System.out.println(e.getMessage());
			} finally {
				if (session != null) {
					session.close();
				}
			}
		}
		return item; 
	}
	public List<Event> getCommingEvent(List<Integer> listEventId, int firstPosition, int maxRecord) {
		List<Event> eventList = new ArrayList<Event>();
		if(listEventId != null){
			String currentTime = EpcsDateTimeUtil.getCurrentIsoDateTime();
			Session session = DBUtil.getSession();
			try {
				Criteria criteria = session.createCriteria(Event.class);
				//Lấy các event trong list eventId, có thời gian bắt đầu trước hiện tại
				Criterion criterion1 = Restrictions.in("eventId", listEventId);
				Criterion criterion2 = Restrictions.gt("startTime", currentTime);
				Criterion criterion3 = Restrictions.eq("status", "confirmed");
				/**
				 * Lấy theo thứ tự thời gian tăng dần, số lượng record phụ thuộc vào firstPosition và maxRecord
				 */
				criteria.add(criterion1).add(criterion2).add(criterion3)
					.addOrder(Order.asc("startTime"))
					.setFirstResult(firstPosition)
					.setMaxResults(maxRecord);
					eventList = criteria.list(); 

			} catch (HibernateException e) {
				System.out.println(e.getMessage());
			} finally {
				if (session != null) {
					session.close();
				}
			}
		}
		return eventList;
	}
	public List<Event> getCloneEvent(Account account,Event originalEvent) {
		List<Event> eventList =  new ArrayList<Event>();
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.eq("originalEvent", originalEvent)).add(Restrictions.eq("account",account));
			eventList = criteria.list();
			if (eventList != null)
				return eventList;
		} finally {

			if (session != null) {
				session.close();
			}
		}
		return null;
	}
	
	public List<Event> getEventListFromDBNotExpired(Account account) {

		Session session = DBUtil.getSession();
		try {
			String currentTime = EpcsDateTimeUtil.getCurrentIsoDateTime();
			Criteria criteria = session.createCriteria(Event.class);
			Criterion criterion2 = Restrictions.gt("startTime", currentTime);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("status", "confirmed"))
			.add(criterion2);							
			criteria.addOrder(Order.asc("startTime"));									
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}
	public List<Event> getEventListByAccount(Account account) {
		String currentTime = EpcsDateTimeUtil.getCurrentIsoDateTime();
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.eq("account", account)).add(Restrictions.eq("status", "confirmed"))
			.add(Restrictions.gt("endTime", currentTime));									
			criteria.addOrder(Order.asc("startTime"));									
			List<Event> item = criteria.list();
			return item;
		} catch (HibernateException e) {
			System.out.println(e.getMessage());
		} finally {
			if (session != null) {
				session.close();
			}
		}

		return null;
	}
	public String getTitleByID(int id) {
		Session session = DBUtil.getSession();
		try {
			Criteria criteria = session.createCriteria(Event.class);
			criteria.add(Restrictions.eq("eventId", id));
			Event item = (Event) criteria.uniqueResult();
			if (item != null)
				return item.getTitle();
		} finally {

			if (session != null) {
				session.close();
			}
		}
		return null;
	}
	
}
